/**
 * 项目名：	Rumba Plan
 * 
 * 版权所有(C)，上海海鼎信息工程股份有限公司，2007，所有权利保留。
 * 
 * 文件名：	OracleSQLReader.java
 * 模块说明：	
 * 修改历史：
 * 2007-2-27 - lxm - 创建。
 */
package com.hd123.rumba.upgrade;

import java.io.BufferedReader;
import java.io.IOException;
import java.util.ArrayList;
import java.util.List;
import java.util.regex.Pattern;

import com.hd123.rumba.exception.BusinessException;

/**
 * 从字符串流中读取Oracle的SQL脚本。
 * 
 * @author lxm
 * 
 */
public class OracleSQLReader implements ISQLReader {

  private BufferedReader in;
  private SQLBlock block = null;

  public OracleSQLReader(BufferedReader in) throws BusinessException {
    super();
    if (in == null)
      throw new BusinessException("参数in不可为空。");
    this.in = in;
  }

  public void close() throws BusinessException {
    if (in == null)
      return;
    try {
      in.close();
      in = null;
      block = null;
    } catch (IOException e) {
      throw new BusinessException(e);
    }
  }

  public SQLBlock readBlock() throws BusinessException {
    if (in == null)
      return null;
    try {
      String line = in.readLine();
      if (line == null)
        return null;
      block = new SQLBlock();
      block.setIgnore(Boolean.FALSE);
      boolean goon = true;
      boolean beginBlock = false;

      while (line != null && goon) {
        List<String> ls = new ArrayList();
        int mode = getLineMode(line, ls);
        switch (mode) {

        case MODE_LINE_DBMS:
          String dbms = ls.get(1).trim();
          if (!CUpgrade.DBMS_ORACLE.equalsIgnoreCase(dbms))
            throw new BusinessException("所标识的DBMS类型不匹配(" + ls.get(1) + ")。");
          break;

        case MODE_LINE_PROMPT:
          block.setAction(SQLBlock.VALUE_ACTION_PROMPT);
          block.setMessage(ls.get(1));
          goon = false;
          break;

        case MODE_LINE_SQL_GO:
          if (beginBlock) {
            if (!"".equals(line.trim()))
              block.getSqls().append(line + "\n");
          } else {
            if (ls.size() > 0 && !"".equals(ls.get(0).trim()))
              block.getSqls().append(ls.get(0));
            block.setAction(SQLBlock.VALUE_ACTION_COMMAND);
            goon = false;
          }
          break;

        case MODE_LINE_IGNORE:
          block.setIgnore(Boolean.TRUE);
          break;

        case MODE_LINE_BEGINBLOCK:
          beginBlock = true;
          block.getSqls().delete(0, block.getSqls().length());
          break;

        case MODE_LINE_BEGINBLOCK_IGNORE:
          beginBlock = true;
          block.setIgnore(Boolean.TRUE);
          block.getSqls().delete(0, block.getSqls().length());
          break;

        case MODE_LINE_ENDBLOCK:
          block.setAction(SQLBlock.VALUE_ACTION_COMMAND);
          goon = false;
          break;

        default: // MODE_LINE_SQL
          if (!"".equals(line.trim()))
            block.getSqls().append(line + "\n");
          break;
        }
        if (goon)
          line = in.readLine();
      }

      return block;
    } catch (IOException e) {
      throw new BusinessException(e);
    }
  }

  /** 行模式：“<code><i>&lt;SQL语句&gt;</i></code>” */
  private static final int MODE_LINE_SQL = -1;
  /** 行模式：“<code>--/dbms:[Oracle|MSSQL|MySQL]</code>” */
  private static final int MODE_LINE_DBMS = 0;
  /** 行模式：“<code>--/p <i>&lt;提示消息&gt;</i></code>” */
  private static final int MODE_LINE_PROMPT = 1;
  /** 行模式：“<code><i>&lt;SQL语句&gt;</i>;</code>” */
  private static final int MODE_LINE_SQL_GO = 2;
  /** 行模式：“<code>;--/ignore</code>” */
  private static final int MODE_LINE_IGNORE = 3;
  /** 行模式：“<code>--/{</code>” */
  private static final int MODE_LINE_BEGINBLOCK = 4;
  /** 行模式：“<code>--/ignore{</code>” */
  private static final int MODE_LINE_BEGINBLOCK_IGNORE = 5;
  /** 行模式：“<code>/</code>” */
  private static final int MODE_LINE_ENDBLOCK = 6;

  private static final String[] REGEXP_MATCHES = new String[] {
      "^\\s*--/dbms:.*", "^\\s*--/p\\s.*", "^.*;\\s*$", "^\\s*--/ignore\\s*$", "^\\s*--/\\{.*",
      "^\\s*--/ignore\\{.*", "^\\s*/\\s*" };

  private static final String[] REGEXP_SPLITS = new String[] {
      "^\\s*--/dbms:", "^\\s*--/p\\s", ";\\s*$", "^\\s*--/ignore\\s*$", "^\\s*--/\\{",
      "^\\s*--/ignore\\{", "^\\s*/\\s*" };

  private int getLineMode(String line, List<String> ls) {
    ls.clear();
    String[] ss = null;

    int mode;
    for (mode = 0; mode < REGEXP_MATCHES.length; mode++) {
      if (Pattern.compile(REGEXP_MATCHES[mode], Pattern.CASE_INSENSITIVE).matcher(line).matches()) {
        ss = Pattern.compile(REGEXP_SPLITS[mode], Pattern.CASE_INSENSITIVE).split(line);
        for (int i = 0; i < ss.length; i++)
          ls.add(ss[i].trim());
        break;
      }
    }
    if (mode < REGEXP_MATCHES.length)
      return mode;
    else
      return MODE_LINE_SQL;
  }

}
